Skip to content

Conversation

@DylanRussell
Copy link
Contributor

@DylanRussell DylanRussell commented Oct 29, 2025

Description

  • Fixes an issue where the instrumentation would crash when a pydantic.BaseModel class was passed as the response schema to GenerateContentConfig, the code expected a class instance for some reason (see BaseModel.model_dump() called on class instead of instance in opentelemetry-instrumentation-google-genai #3596).
  • Ensures the same Sem Conv attributes are added to the Log and the Span. The gen AI semantic conventions are basically the same for log events and spans. Adds the error.type sem conv attribute when there's an exception raised.
  • Moves the _maybe_log_completion_details( function call into the finally block for the 4 instrumentation variants (sync/async streaming/non). This ensures we always write the event and call the completion hook etc. even when there's an exception thrown.
  • Ensure the new gen_ai.client.inference.operation.details log event is written and completion upload hook are called when OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental.
  • Some code cleanup / refactoring.

Fixes #3596

Type of change

Please delete options that are not relevant.

  • [ x] Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

Unit tests

Does This PR Require a Core Repo Change?

  • Yes. - Link to PR:
  • [ x] No.

Checklist:

See contributing.md for styleguide, changelog guidelines, and more.

  • [x ] Followed the style guidelines of this project
  • [x ] Changelogs have been updated
  • [ x] Unit tests have been added
  • Documentation has been updated

@DylanRussell DylanRussell requested a review from a team as a code owner October 29, 2025 20:24
@DylanRussell DylanRussell changed the title Fix a few bugs in gen AI instrumentation Fix a few bugs in the Google gen AI instrumentation Oct 29, 2025
@DylanRussell DylanRussell changed the title Fix a few bugs in the Google gen AI instrumentation Fix a few bugs in opentelemetry-instrumentation-google-genai instrumentation package Oct 29, 2025
Comment on lines 164 to +169
if hasattr(value, "model_dump"):
return value.model_dump()
try:
return value.model_dump()
except TypeError:
return {"ModelName": str(value)}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just make this function typed since we know we're receiving GenerateContentConfigOrDict? I think it's "provable" that we don't need this hasattr check and that the call is correct

One issue is I don't think this file is opted in to pyright 🙁 but doesn't change the implementation

if config.response_mime_type:
if config.response_mime_type == "text/plain":
response_mime_type = config.get("response_mime_type")
if response_mime_type and is_experimental_mode:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this make the GEN_AI_OUTPUT_TYPE go away for people not using experimental semconv?

Looking at the test seems like none of the "old" semconv changes

config.response_mime_type
response_mime_type
)
for key in list(attributes.keys()):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for key in list(attributes.keys()):
for key in attributes:

self,
request_attributes: dict[str, Any],
final_attributes: dict[str, Any],
is_experimental_mode: bool,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can just use self.sem_conv_opt_in_mode

Comment on lines +730 to +732
span.set_attribute(
gen_ai_attributes.GEN_AI_SYSTEM, helper._genai_system
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised helper doesn't set this itself, that would be simpler imo. Feel free to disregard not too familiar with this code

def configure_exception(self, e, **kwargs):
self._create_and_install_mocks(e)

def _create_and_install_mocks_with(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't look like this function is used

Comment on lines +129 to +132
if not e:
mock.side_effect = _default_impl
else:
mock.side_effect = e
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit feel free to ignore

Suggested change
if not e:
mock.side_effect = _default_impl
else:
mock.side_effect = e
mock.side_effect = e or _default_impl

Comment on lines +114 to +118
try:
self.generate_content(
model="gemini-2.0-flash", contents="Does this work?"
)
except ValueError:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BaseModel.model_dump() called on class instead of instance in opentelemetry-instrumentation-google-genai

6 participants